module ucordic8decoder (ADDR, DME, DEM, nRD, nWE, nCS, nIDLE, nRESET, CLK, SELMUXEXTREGX, SELMUXEXTREGY, SELMUXEXTREGZ, SELMUXREGEXT, ENX, ENY, ENZ, nCTRHOLD, ApproxMode, CoordMode, DataToCordicCore, DataFromCordicCore, nResetToCordicCore);

input [1:0] ADDR;
input [7:0] DME;
output [7:0] DEM;
input nRD, nWE, nCS;
output nIDLE;

input nRESET, CLK;

output [1:0] SELMUXREGEXT;
output SELMUXEXTREGX, SELMUXEXTREGY, SELMUXEXTREGZ, ENX, ENY, ENZ, nCTRHOLD;
output [1:0] CoordMode;
output ApproxMode;
output [7:0] DataToCordicCore;
input [7:0] DataFromCordicCore;
output nResetToCordicCore;

wire [1:0] ADDR;
wire [7:0] DME;
reg [7:0] DEM;
wire nRD, nWE, nCS;
reg nIDLE;

wire CLK, nRESET;

reg [1:0] SELMUXREGEXT;
reg SELMUXEXTREGX, SELMUXEXTREGY, SELMUXEXTREGZ, ENX, ENY, ENZ, nCTRHOLD;
reg [1:0] CoordMode;
reg ApproxMode;
reg [7:0] DataToCordicCore;
wire [7:0] DataFromCordicCore;
reg nResetToCordicCore;

reg [7:0] regState;
reg [7:0] regCMD, regDME, regDEM;
reg sigCmdReady, sigClrCmdReady;

parameter IDLE = 8'h00;
parameter SETX_SET = 8'h01, SETY_SET = 8'h02, SETZ_SET = 8'h03, SETX_REL = 8'h04, SETY_REL = 8'h05, SETZ_REL = 8'h06;
parameter CALC_CAL1 = 8'h11, CALC_CU1 = 8'h12, CALC_CAL2 = 8'h13, CALC_CU2 = 8'h14, CALC_CAL3 = 8'h15, CALC_CU3 = 8'h16, CALC_CAL4 = 8'h17, CALC_CU4 = 8'h18, CALC_CAL5 = 8'h19, CALC_CU5 = 8'h1a, CALC_CAL6 = 8'h1b, CALC_CU6 = 8'h1c, CALC_CAL7 = 8'h1d, CALC_CU7 = 8'h1e, CALC_CAL8 = 8'h1f, CALC_CU8 = 8'h20, CALC_REL = 8'h10;
parameter GETX_SET = 8'h30, GETY_SET = 8'h31, GETZ_SET = 8'h32, GET_REL = 8'h33;
parameter RESET_SET = 8'h40, RESET_REL = 8'h41;

always @ (negedge nRESET or negedge nRD or negedge nWE or posedge nCS or posedge sigClrCmdReady)
begin
	if (nRESET == 1'b0)
	begin /*async reset*/
		regDME <= 8'b0;
		regCMD <= 8'b0;
		DEM <= 8'bz;
		sigCmdReady <= 1'b0;
	end
	else
	begin
		if (nCS == 1'b1)
		begin /*chip not selected*/
			DEM <= 8'bz;
		end
		else
		begin
			if (sigClrCmdReady == 1'b1)
			begin
				sigCmdReady <= 1'b0;
				DEM <= 8'bz;
			end
			else
			begin
				if (nRD == 1'b0) /*READ to master*/
				begin
					case (ADDR)
					2'b10: /*regDEM*/
						DEM <= regDEM;
					default:
						DEM <= 8'bx;
					endcase
				end
				else if (nWE == 1'b0) /*WRITE to slave*/
				begin
					case (ADDR)
					2'b00: /*regDME*/
					begin
						regDME <= DME;
					end
					2'b01: /*regCMD*/
					begin
						regCMD <= DME;
						sigCmdReady <= 1'b1;
					end
					default:
					begin
						regDME <= 8'bx;
						regCMD <= 8'bx;
					end
					endcase
					DEM <= 8'bz;
				end
				else
				begin
					DEM <= 8'bz;
				end
			end
		end
	end
end

always @(negedge CLK or negedge nRESET)
begin
	if (nRESET == 1'b0)
	begin /*async reset*/
		SELMUXREGEXT <= 2'b00;
		SELMUXEXTREGX <= 1'b0;
		SELMUXEXTREGY <= 1'b0;
		SELMUXEXTREGZ <= 1'b0;
		ENX <= 1'b0;
		ENY <= 1'b0;
		ENZ <= 1'b0;
		nCTRHOLD <= 1'b0;
		CoordMode <= 2'b00;
		ApproxMode <= 1'b0;
		DataToCordicCore <= 8'h00;
		nResetToCordicCore <= 1'b1;
		regState <= IDLE;
		sigClrCmdReady <= 1'b0;
		nIDLE <= 1'b0;
		regDEM = 8'h00;
		regState <= IDLE;
	end
	else
	begin /*normal ops*/
		if (sigCmdReady == 1'b1)
		begin /*New command arrives*/
			sigClrCmdReady <= 1'b1;
			case (regCMD)
			8'b00010000, 8'b00010001, 8'b00010011, 8'b00010100, 8'b00010101, 8'b00010111: /*CALC*/
			begin
				regState <= CALC_CAL1;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				SELMUXEXTREGX <= 1'b0;
				SELMUXEXTREGY <= 1'b0;
				SELMUXEXTREGZ <= 1'b0;
				nCTRHOLD <= 1'b0;
				CoordMode <= {regCMD[1], regCMD[0]};
				ApproxMode <= regCMD[2];
				nIDLE <= 1'b1;
			end
			8'b00000100: /*SETX*/
			begin
				regState <= SETX_SET;
				ENX <= 1'b1;
				DataToCordicCore <= regDME;
				SELMUXEXTREGX <= 1'b1;
				nIDLE <= 1'b1;
			end
			8'b00000101: /*SETY*/
			begin
				regState <= SETY_SET;
				ENY <= 1'b1;
				DataToCordicCore <= regDME;
				SELMUXEXTREGY <= 1'b1;
				nIDLE <= 1'b1;
			end
			8'b00000110: /*SETZ*/
			begin
				regState <= SETZ_SET;
				ENZ <= 1'b1;
				DataToCordicCore <= regDME;
				SELMUXEXTREGZ <= 1'b1;
				nIDLE <= 1'b1;
			end
			8'b00001100: /*GETX*/
			begin
				regState <= GETX_SET;
				SELMUXREGEXT <= 2'b00;
				nIDLE <= 1'b1;
			end
			8'b00001101: /*GETY*/
			begin
				regState <= GETY_SET;
				SELMUXREGEXT <= 2'b01;
				nIDLE <= 1'b1;
			end
			8'b00001110: /*GETZ*/
			begin
				regState <= GETZ_SET;
				SELMUXREGEXT <= 2'b10;
				nIDLE <= 1'b1;
			end
			8'b00000000: /*RESET*/
			begin
				regState <= RESET_SET;
				nResetToCordicCore <= 1'b0;
				nIDLE <= 1'b1;
			end
			endcase
		end
		else
		begin
			sigClrCmdReady <= 1'b0;
			case (regState)
			CALC_CAL1:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU1;
			end
			CALC_CAL2:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU2;
			end
			CALC_CAL3:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU3;
			end
			CALC_CAL4:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU4;
			end
			CALC_CAL5:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU5;
			end
			CALC_CAL6:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU6;
			end
			CALC_CAL7:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU7;
			end
			CALC_CAL8:
			begin
				nCTRHOLD <= 1'b1;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				regState <= CALC_CU8;
			end
			CALC_CU1:
			begin
				regState <= CALC_CAL2;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU2:
			begin
				regState <= CALC_CAL3;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU3:
			begin
				regState <= CALC_CAL4;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU4:
			begin
				regState <= CALC_CAL5;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU5:
			begin
				regState <= CALC_CAL6;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU6:
			begin
				regState <= CALC_CAL7;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU7:
			begin
				regState <= CALC_CAL8;
				ENX <= 1'b1;
				ENY <= 1'b1;
				ENZ <= 1'b1;
				nCTRHOLD = 1'b0;
			end
			CALC_CU8:
			begin
				regState <= CALC_REL;
				ENX <= 1'b0;
				ENY <= 1'b0;
				ENZ <= 1'b0;
				nCTRHOLD = 1'b0;
			end
			CALC_REL:
			begin
				regState <= IDLE;
				nIDLE <= 1'b0;
			end
			SETX_SET:
			begin
				regState <= SETX_REL;
				ENX <= 1'b0;
				DataToCordicCore <= 8'hxx;
				SELMUXEXTREGX <= 1'bx;
			end
			SETY_SET:
			begin
				regState <= SETY_REL;
				ENY <= 1'b0;
				DataToCordicCore <= 8'hxx;
				SELMUXEXTREGY <= 1'bx;
			end
			SETZ_SET:
			begin
				regState <= SETZ_REL;
				ENZ <= 1'b0;
				DataToCordicCore <= 8'hxx;
				SELMUXEXTREGZ <= 1'bx;
			end
			SETX_REL, SETY_REL, SETZ_REL:
			begin
				regState <= IDLE;
				nIDLE <= 1'b0;
			end
			GETX_SET, GETY_SET, GETZ_SET:
			begin
				regState <= GET_REL;
				regDEM <= DataFromCordicCore;
			end
			GET_REL:
			begin
				regState <= IDLE;
				nIDLE = 1'b0;
			end
			RESET_SET:
			begin
				regState <= RESET_REL;
				nResetToCordicCore <= 1'b0;
			end
			RESET_REL:
			begin
				regState <= IDLE;
				nResetToCordicCore <= 1'b1;
				nIDLE <= 1'b0;
			end
			endcase
		end
	end
end

endmodule
